`timescale 1ns/100ps

`include "sim_glb.sv"

module tc;

localparam          CLK_PRD                 = 5;
localparam          DW                      = 32;       // original data width, 1<=DW<=502
localparam          CW                      = ecc_cw_f(DW, "SEC_ONLY");

reg                                         rst_n;
reg                                         clk;

reg                                         frc_sbe;    // force single-bit error
reg                 [DW-1:0]                od;         // original data
wire                [DW+CW-1:0]             cd;         // coded data
reg                 [DW+CW-1:0]             e;
wire                [DW+CW-1:0]             cd_e;
wire                [DW-1:0]                d_cor;
wire                [CW-1:0]                s;          // syndrom
wire                                        err;        // good coded data
reg                                         err_flag;
reg                 [CW-1:0]                s_1d;
reg                                         err_1d;

initial begin:CRG
    rst_n=1'b0;
    clk=1'b0;

    fork
        rst_n=#100.5 1'b1;
        forever clk=#CLK_PRD ~clk;
    join
end

RGRS_MNG    rgrs;
initial begin:REGRESS
    rgrs = new("tc_sec_only", 1);

    rgrs.wait_chks_done(100_000_000);
end

initial begin:DISP_G
    integer i, j;
    integer wght;

    @(posedge rst_n);

    $display("\n%m G matrix for (%0d, %0d) SEC_DED code:", (DW+CW), DW);
    for (i=0; i<CW; i=i+1) begin
        wght = 0;
        for (j=0; j<DW; j=j+1) begin
            if (u_enc.gm_ary[i*DW+j]==1'b1) begin
                wght = wght + 1'd1;
            end
        end
        $display("S[%2d]:%b (%0d)", i, u_enc.gm_ary[i*DW+:DW], wght);
    end
end

initial begin:GEN_
    od = {DW{1'b0}};

    @(posedge rst_n);

    repeat(10000) begin
        @(posedge clk);
        `U_DLY;
        od = $urandom();
        repeat((DW-1)/32) begin
            od = (od<<32) | $urandom();
        end
    end
    #100;
    rgrs.one_chk_done("gen od is done.");
end

initial begin:FRC_ERR
    integer p1;

    frc_sbe = 1'b0;
    e = {DW+CW{1'b0}};
    
    @(posedge rst_n);
    #10_000;

    forever begin
        @(posedge clk);
        `U_DLY;
        p1 = $urandom_range(0, DW+CW-1);
        e = (1<<p1);
    end
end

sec_only_enc #(
        .DW                             (DW                             ) 	// original data width, 1<=DW<=502
) u_enc ( 
        .frc_sbe                        (frc_sbe                        ),	// force single-bit error
        .od                             (od                             ),	// original data
        .cd                             (cd                             )	// coded data
);

assign cd_e = cd ^ e;
sec_only_dec #(
        .DW                             (DW                             ) 	// original data width, 1<=DW<=502
) u_dec ( 
        .cd                             (cd_e                           ),	// coded data
        .od                             (d_cor                          ),	// original data
        .s                              (s                              ),	// syndrom
        .err                            (err                            ) 	// good coded data
);

always@(posedge clk or negedge rst_n) begin
    if (rst_n==1'b0) begin
        err_flag <=`U_DLY 1'b0;
    end else begin
        if (d_cor!=od) begin
            err_flag <=`U_DLY 1'b1;
            $error("d_cor %0h is not same to od %0h", d_cor, od);
        end else
            err_flag <=`U_DLY 1'b0;
    end
end

always@(posedge clk or negedge rst_n) begin
    if (rst_n==1'b0) begin
        s_1d   <=`U_DLY {CW{1'b0}};
        err_1d <=`U_DLY 1'b0;
    end else begin
        s_1d   <=`U_DLY s;
        err_1d <=`U_DLY err;
    end
end

`include "func_ecc.v"   // refer to ecc_cw_f()

endmodule

